package com.gzhryc.shared_device.oem.code;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.request.AlipayUserInfoShareRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.alipay.api.response.AlipayUserInfoShareResponse;
import com.gzhryc.common.ClassTools;
import com.gzhryc.common.StringTools;
import com.gzhryc.common.logging.Logger;
import com.gzhryc.pay.adaptation.alipay.AlipayAdvancePayService;
import com.gzhryc.pay.adaptation.alipay.AlipayNativeService;
import com.gzhryc.pay.adaptation.alipay.AlipayNormalPayService;
import com.gzhryc.pay.adaptation.alipay.DefaultAlipayConfig;
import com.gzhryc.pay.adaptation.weixin.DefaultWXPayConfig;
import com.gzhryc.pay.adaptation.weixin.WXPayAdvancePayService;
import com.gzhryc.pay.adaptation.weixin.WXPayNativeService;
import com.gzhryc.pay.adaptation.weixin.WXPayNormalPayService;
import com.gzhryc.shared_device.base.IMemberWalletService;
import com.gzhryc.shared_device.base.IPayServiceFactory;
import com.gzhryc.shared_device.common.payment.dao.db.AlipayConfig;
import com.gzhryc.shared_device.common.payment.dao.db.WXPayConfig;
import com.gzhryc.shared_device.common.payment.services.AlipayConfigService;
import com.gzhryc.shared_device.common.payment.services.WXPayConfigService;
import com.gzhryc.shared_device.oem.code.business.EBusinessType;
import com.gzhryc.shared_device.oem.code.member.services.MemberWalletService;

import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang3.StringUtils;

/**
 * 支付服务工厂
 * @author zhanghao
 * @version 2021-10-05
 */
public class PayServiceFactory implements IPayServiceFactory {

	static Logger log = Logger.getLogger(PayServiceFactory.class);

	static PayServiceFactory me;

	public static PayServiceFactory self(){
		if(me == null){
			me = new PayServiceFactory();
		}
		return me;
	}
	
	private ConcurrentHashMap<String, AppConfig> configStore = new ConcurrentHashMap<>();

	private ConcurrentHashMap<String, WXPayNormalPayService> wxNormalPayServiceStore = new ConcurrentHashMap<>();
	private ConcurrentHashMap<String, WXPayAdvancePayService> wxAdvancePayServiceStore = new ConcurrentHashMap<>();
	private ConcurrentHashMap<String, WXPayNativeService> wxNativePayServiceStore = new ConcurrentHashMap<>();
	
	private ConcurrentHashMap<String, AlipayClient> alipayClientStore = new ConcurrentHashMap<>();
	private ConcurrentHashMap<String, AlipayNormalPayService> aliNormalPayServiceStore = new ConcurrentHashMap<>();
	private ConcurrentHashMap<String, AlipayAdvancePayService> aliAdvancePayServiceStore = new ConcurrentHashMap<>();
	private ConcurrentHashMap<String, AlipayNativeService> aliNativePayServiceStore = new ConcurrentHashMap<>();
	
	private String httpDomain;

	public void initial(String httpDomain){
		this.httpDomain = httpDomain;
	}

	public DefaultWXPayConfig getWXPayConfig(String appId,String businessType){
		if (StringTools.isNotBlank(appId) && StringTools.isNotBlank(businessType)) {
			WXPayConfig config = null;
			AppConfig appConfig = configStore.get(appId);
			if(appConfig != null && appConfig.getWxpayConfig() != null){
				config = appConfig.getWxpayConfig();
			}else {
				config = WXPayConfigService.self(BaseConstants.JDBC_KEY).getByAppId(appId);
				if(config != null) {
					configStore.put(appId, new AppConfig(config));
				}
			}
			
			if(config != null) {
				DefaultWXPayConfig wxpayConfig = ClassTools.copy(new DefaultWXPayConfig(), config);
				if(EBusinessType.RECHARGE.index().equals(businessType)){
					wxpayConfig.setPayNotifyUrl(httpDomain + "/paycall/recharge/wxpay/" + appId + "/pay");
					wxpayConfig.setRefundNotifyUrl(httpDomain + "/paycall/recharge/wxpay/" + appId + "/refund");
				}else if(EBusinessType.MARKET.index().equals(businessType)){
					wxpayConfig.setPayNotifyUrl(httpDomain + "/paycall/market/wxpay/" + appId + "/pay");
					wxpayConfig.setRefundNotifyUrl(httpDomain + "/paycall/market/wxpay/" + appId + "/refund");
				}else {
					wxpayConfig.setPayNotifyUrl(httpDomain + "/paycall/" + businessType.toLowerCase() + "/wxpay/" + appId + "/pay");
					wxpayConfig.setRefundNotifyUrl(httpDomain + "/paycall/" + businessType.toLowerCase() + "/wxpay/" + appId + "/refund");
					wxpayConfig.setPreAuthNotifyUrl(httpDomain + "/paycall/" + businessType.toLowerCase() + "/wxpay/" + appId + "/rentbill");
				}
				return wxpayConfig;
			}
		}
		return null;
	}
	
	public DefaultAlipayConfig getAlipayConfig(String appId,String businessType){
		if (StringTools.isNotBlank(appId) && StringTools.isNotBlank(businessType)) {
			AlipayConfig config = null;
			AppConfig appConfig = configStore.get(appId);
			if(appConfig != null && appConfig.getAlipayConfig() != null){
				config = appConfig.getAlipayConfig();
			}else {
				config = AlipayConfigService.self(BaseConstants.JDBC_KEY).getByAppId(appId);
				if(config != null) {
					configStore.put(appId, new AppConfig(config));
				}
			}
			
			if(config != null) {
				DefaultAlipayConfig alipayConfig = ClassTools.copy(new DefaultAlipayConfig(), config);
				if(EBusinessType.RECHARGE.index().equals(businessType)){
					alipayConfig.setPayNotifyUrl(httpDomain + "/paycall/recharge/alipay/" + appId + "/pay");
				}else if(EBusinessType.MARKET.index().equals(businessType)){
					alipayConfig.setPayNotifyUrl(httpDomain + "/paycall/market/alipay/" + appId + "/pay");
				}else {
					alipayConfig.setPayNotifyUrl(httpDomain + "/paycall/"+ businessType.toLowerCase() + "/alipay/" + appId + "/pay");
					alipayConfig.setPreAuthNotifyUrl(httpDomain + "/paycall/" + businessType.toLowerCase() + "/alipay/" + appId + "/rentbill");
					alipayConfig.setPreAuthPayNotifyUrl(httpDomain + "/paycall/" + businessType.toLowerCase() + "/alipay/" + appId + "/rentbill/pay");
				}
				return alipayConfig;
			}
		}
		return null;
	}

	public AppConfig getWxConfig(String appId){
		if(StringTools.isNotBlank(appId)) {
			AppConfig appConfig = configStore.get(appId);
			if(appConfig == null) {
				WXPayConfig config = WXPayConfigService.self(BaseConstants.JDBC_KEY).getByAppId(appId);
				if(config != null) {
					appConfig = new AppConfig(config);
					configStore.put(appId, appConfig);
				}
			}
			return appConfig;
		}
		return null;
	}
	
	public AppConfig getAliConfig(String appId){
		if(StringTools.isNotBlank(appId)) {
			AppConfig appConfig = configStore.get(appId);
			if(appConfig == null) {
				AlipayConfig config = AlipayConfigService.self(BaseConstants.JDBC_KEY).getByAppId(appId);
				if(config != null) {
					appConfig = new AppConfig(config);
					configStore.put(appId, appConfig);
				}
			}
			return appConfig;
		}
		return null;
	}

	public AlipayClient getAlipayClient(String appId) {
        if (StringTools.isNotBlank(appId)) {
        	AlipayClient alipayClient =  alipayClientStore.get(appId);
        	if(alipayClient == null) {
        		AlipayConfig config = AlipayConfigService.self(BaseConstants.JDBC_KEY).getByAppId(appId);
    			if(config != null) {
		            if (StringUtils.isNotBlank(config.getAppId()) && StringUtils.isNotBlank(config.getAppPrivateKey())
		            		&& StringUtils.isNotBlank(config.getCertificatePath())) {
		            	/**公钥证书方式 转账需要***/
		                CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
		                certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");
		                certAlipayRequest.setAppId(config.getAppId());
		                certAlipayRequest.setPrivateKey(config.getAppPrivateKey());
		                certAlipayRequest.setFormat("json");
		                certAlipayRequest.setCharset("UTF-8");
		                certAlipayRequest.setSignType("RSA2");
		                certAlipayRequest.setCertPath(config.getCertificatePath() + config.getAppId() + java.io.File.separator + "appCertPublicKey.crt");
		                certAlipayRequest.setAlipayPublicCertPath(config.getCertificatePath() + config.getAppId() + java.io.File.separator + "alipayCertPublicKey_RSA2.crt");
		                certAlipayRequest.setRootCertPath(config.getCertificatePath() + config.getAppId() + java.io.File.separator + "alipayRootCert.crt");
		                
		                try {
		                	alipayClient = new DefaultAlipayClient(certAlipayRequest);
		                } catch (AlipayApiException e) {
		                    log.error(e.getMessage(), e);
		                }
		            } else {
		            	alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", config.getAppId(),
		                        config.getAppPrivateKey(), "json", "UTF-8", config.getAlipayPublicKey(), "RSA2");
		            }
		            
		            if(alipayClient != null) {
		            	alipayClientStore.put(appId, alipayClient);
		            }
    			}
        	}
        	return alipayClient;
        }
        return null;
    }
	
	public AlipaySystemOauthTokenResponse getOauthAccessToken(String appId,String authCode) {
		AlipayClient alipayClient = getAlipayClient(appId);
		if (alipayClient != null) {
			AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
			request.setCode(authCode);
			request.setGrantType("authorization_code");
			try {
				AlipaySystemOauthTokenResponse oauthTokenResponse = null;
				//默认使用充值支付配置
				DefaultAlipayConfig config = this.getAlipayConfig(appId, EBusinessType.RECHARGE.index());
				if (StringUtils.isNotBlank(config.getCertificatePath())) {
					oauthTokenResponse = alipayClient.certificateExecute(request);
				} else {
					oauthTokenResponse = alipayClient.execute(request);
				}
				if (oauthTokenResponse != null && oauthTokenResponse.isSuccess()) {
					return oauthTokenResponse;
				}
			} catch (AlipayApiException e) {
				log.error("支付宝登陆获取Token异常", e);
			}
		}
		return null;
	}
	
	public AlipayUserInfoShareResponse getAlipayUserInfo(String appId,AlipaySystemOauthTokenResponse tokenResponse) {
		AlipayClient alipayClient = getAlipayClient(appId);
		if (alipayClient != null) {
			AlipayUserInfoShareRequest request = new AlipayUserInfoShareRequest();
			try {
				AlipayUserInfoShareResponse response = null;
				//默认使用充值支付配置
				DefaultAlipayConfig config = this.getAlipayConfig(appId, EBusinessType.RECHARGE.index());
				if (StringUtils.isNotBlank(config.getCertificatePath())) {
					response = alipayClient.certificateExecute(request, tokenResponse.getAccessToken());
				} else {
					response = alipayClient.execute(request, tokenResponse.getAccessToken());
				}
				log.info("支付宝登陆返回：{{0:json}}",response);
				if (response != null && response.isSuccess()) {
					return response;
				}
			} catch (AlipayApiException e) {
				log.error("支付宝登陆异常", e);
			}
		}
		return null;
	}
	
	@Override
	public IMemberWalletService getMemberWalletService() {
		return MemberWalletService.self();
	}
	
	@Override
	public WXPayNormalPayService getWXPayNormalPayService(String appId, String businessType) {
		if (StringTools.isNotBlank(appId) && StringTools.isNotBlank(businessType)) {
			String key = appId + "_" + businessType;
			WXPayNormalPayService payService = wxNormalPayServiceStore.get(key);
			if (payService == null) {
				DefaultWXPayConfig wxpayConfig = getWXPayConfig(appId, businessType);
				if (wxpayConfig != null) {
					payService = new WXPayNormalPayService(wxpayConfig);
					wxNormalPayServiceStore.put(key, payService);
				}
			}
			return payService;
		}
		return null;
	}
	
	@Override
	public WXPayAdvancePayService getWXPayAdvancePayService(String appId, String businessType) {
		if (StringTools.isNotBlank(appId) && StringTools.isNotBlank(businessType)) {
			String key = appId + "_" + businessType;
			WXPayAdvancePayService payService = wxAdvancePayServiceStore.get(key);
			if (payService == null) {
				DefaultWXPayConfig wxpayConfig = getWXPayConfig(appId, businessType);
				if (wxpayConfig != null) {
					payService = new WXPayAdvancePayService(wxpayConfig);
					wxAdvancePayServiceStore.put(key, payService);
				}
			}
			return payService;
		}
		return null;
	}
	
	@Override
	public WXPayNativeService getWXPayNativePayService(String appId, String businessType){
		if (StringTools.isNotBlank(appId) && StringTools.isNotBlank(businessType)) {
			String key = appId + "_" + businessType;
			WXPayNativeService payService = wxNativePayServiceStore.get(key);
			if (payService == null) {
				DefaultWXPayConfig wxpayConfig = getWXPayConfig(appId, businessType);
				if (wxpayConfig != null) {
					payService = new WXPayNativeService(wxpayConfig);
					wxNativePayServiceStore.put(key, payService);
				}
			}
			return payService;
		}
		return null;
	}

	@Override
	public AlipayNormalPayService getAlipayNormalPayService(String appId, String businessType) {
		if (StringTools.isNotBlank(appId) && StringTools.isNotBlank(businessType)) {
			String key = appId + "_" + businessType;
			AlipayNormalPayService payService = aliNormalPayServiceStore.get(key);
			if (payService == null) {
				DefaultAlipayConfig alipayConfig = getAlipayConfig(appId, businessType);
				if (alipayConfig != null) {
					payService = new AlipayNormalPayService(alipayConfig);
					aliNormalPayServiceStore.put(key, payService);
				}
			}
			return payService;
		}
		return null;
	}

	@Override
	public AlipayAdvancePayService getAlipayAdvancePayService(String appId, String businessType) {
		if (StringTools.isNotBlank(appId) && StringTools.isNotBlank(businessType)) {
			String key = appId + "_" + businessType;
			AlipayAdvancePayService payService = aliAdvancePayServiceStore.get(key);
			if (payService == null) {
				DefaultAlipayConfig alipayConfig = getAlipayConfig(appId, businessType);
				if (alipayConfig != null) {
					payService = new AlipayAdvancePayService(alipayConfig);
					aliAdvancePayServiceStore.put(key, payService);
				}
			}
			return payService;
		}
		return null;
	}

	@Override
	public AlipayNativeService getAlipayNativePayService(String appId, String businessType) {
		if (StringTools.isNotBlank(appId) && StringTools.isNotBlank(businessType)) {
			String key = appId + "_" + businessType;
			AlipayNativeService payService = aliNativePayServiceStore.get(key);
			if (payService == null) {
				DefaultAlipayConfig wxpayConfig = getAlipayConfig(appId, businessType);
				if (wxpayConfig != null) {
					payService = new AlipayNativeService(wxpayConfig);
					aliNativePayServiceStore.put(key, payService);
				}
			}
			return payService;
		}
		return null;
	}
	
	public static class AppConfig {

		private String appId;
		private String appSecret;
		
		private WXPayConfig wxpayConfig;
		private AlipayConfig alipayConfig;
		
		public AppConfig(WXPayConfig wxpayConfig) {
			this.appId = wxpayConfig.getAppId();
			this.appSecret = wxpayConfig.getAppSecret();
			this.wxpayConfig = wxpayConfig;
		}
		
		public AppConfig(AlipayConfig alipayConfig) {
			this.appId = alipayConfig.getAppId();
			this.appSecret = alipayConfig.getXcxDecryptKey();
			this.alipayConfig = alipayConfig;
		}
		
		public String getAppId() {
			return appId;
		}

		public void setAppId(String appId) {
			this.appId = appId;
		}

		public String getAppSecret() {
			return appSecret;
		}

		public void setAppSecret(String appSecret) {
			this.appSecret = appSecret;
		}

		public WXPayConfig getWxpayConfig() {
			return wxpayConfig;
		}

		public void setWxpayConfig(WXPayConfig wxpayConfig) {
			this.wxpayConfig = wxpayConfig;
		}

		public AlipayConfig getAlipayConfig() {
			return alipayConfig;
		}

		public void setAlipayConfig(AlipayConfig alipayConfig) {
			this.alipayConfig = alipayConfig;
		}
	}
}
